#include <iostream>
#include <sstream>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/video.hpp>
using namespace cv;
using namespace std;
const char* params
    = "{ help h         |           | Print usage }"
      "{ input          | test.avi  | Path to a video or a sequence of image }"
      "{ lr             | -1        | learning rate of MOG2 }"
      "{ algo           | MOG2      | Background subtraction method (KNN, MOG2) }"
      "{ threshold      | 16        | threshold  default:KNN 400 MOG2 16 }";
Mat convertTo3Channels(const Mat& binImg)
{
    Mat three_channel = Mat::zeros(binImg.rows,binImg.cols,CV_8UC3);
    vector<Mat> channels;
    for (int i=0;i<3;i++)
    {
        channels.push_back(binImg);
    }
    merge(channels,three_channel);
    return three_channel;
}
int main(int argc, char* argv[])
{
    CommandLineParser parser(argc, argv, params);
    parser.about( "This program shows how to use background subtraction methods provided by "
                  " OpenCV. You can process both videos and images.\n" );
    if (parser.has("help"))
    {
        //print help information
        parser.printMessage();
        return 0;
    }
    //create Background Subtractor objects
    Ptr<BackgroundSubtractor> pBackSub;
    double lr = parser.get<double>("lr");
    double threshold = parser.get<double>("threshold");
    if (parser.get<String>("algo") == "MOG2")
        pBackSub = createBackgroundSubtractorMOG2(lr,threshold);
    else
        pBackSub = createBackgroundSubtractorKNN(lr,threshold);
    VideoCapture capture( samples::findFile( parser.get<String>("input") ) );
    if (!capture.isOpened()){
        //error in opening the video input
        cerr << "Unable to open: " << parser.get<String>("input") << endl;
        return 0;
    }
    Mat frame, fgMask;
    VideoWriter videoWriter;
    Size S = Size((int)capture.get(CAP_PROP_FRAME_WIDTH),(int)capture.get(CAP_PROP_FRAME_HEIGHT));
	int fps = capture.get(CAP_PROP_FPS);
    string output = "output_display.avi"
	videoWriter.open(output, cv::VideoWriter::fourcc('M','J','P','G'),fps ,S);
    while (true) {
        capture >> frame;
        if (frame.empty())
            break;
        //update the background model
        pBackSub->apply(frame, fgMask);
        //get the frame number and write it on the current frame
        /*
        rectangle(frame, cv::Point(10, 2), cv::Point(100,20),cv::Scalar(255,255,255), -1);
        stringstream ss;
        ss << capture.get(CAP_PROP_POS_FRAMES);
        string frameNumberString = ss.str();
        putText(frame, frameNumberString.c_str(), cv::Point(15, 15),
                FONT_HERSHEY_SIMPLEX, 0.5 , cv::Scalar(0,0,0));
        */
        //show the current frame and the fg masks
        imshow("Frame", frame);
        imshow("FG Mask", fgMask);
        /*
	int kernel_size = 3;
	Mat kernel_1 = getStructuringElement(MORPH_RECT, Size(kernel_size, kernel_size), Point(-1, -1));
	Mat dst1;
	morphologyEx(fgMask, dst1, MORPH_TOPHAT, kernel_1, Point(-1, -1), 1, 0);
	namedWindow("顶帽", WINDOW_FREERATIO);
	imshow("顶帽", dst1);
	*/
	
	Mat se = getStructuringElement(0,Size(2,2) ); //构造矩形结构元素
	erode(fgMask, fgMask, se, Point(-1, -1), 2); //执行腐蚀操作
	dilate(fgMask, fgMask, se, Point(-1, -1), 2); //执行膨胀操作
	vector<std::vector<cv::Point>> contours;
	findContours(fgMask, contours, RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
    	for (int i = 0; i < contours.size(); ++i)
    	{
      	//判断轮廓大小，当大于1000时进入
      	if(cv::contourArea(contours[i])>50)
      	{
        //获取轮廓矩形
        	cv::Rect rect=cv::boundingRect(contours[i]);
        //在矩形的左上角点输出文字
        	cv::putText(fgMask, to_string(contourArea(contours[i])), cv::Point(rect.x,rect.y),
          	FONT_HERSHEY_PLAIN, 2, cv::Scalar(255, 255, 255));
      	}
    	}
	imshow("open ", fgMask);
    	
	if(parser.has("output"))videoWriter.write(convertTo3Channels(fgMask));
        //get the input from the keyboard
        int keyboard = waitKey(30);
        if (keyboard == 'q' || keyboard == 27)
            break;
    }
    videoWriter.release();
    return 0;
}
